package org.az.netty_study.p03_nio组件之selector._1_单线程的阻塞模式;

import lombok.extern.slf4j.Slf4j;
import org.az.netty_study.ByteBufferUtil;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.List;

/**
 * 使用nio来理解阻塞模式
 * 下面演示了单线程的阻塞服务器
 */
@Slf4j
public class Server {
    public static void main(String[] args) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(16);
        //1.创建了服务器
        ServerSocketChannel ssc = ServerSocketChannel.open();
        //2.绑定监听端口
        ssc.bind(new InetSocketAddress(9999));
        List<SocketChannel> channels = new ArrayList<>(); //连接可能有多个，该集合保存所有连接
        while (true) {
            /**
             * 3.建立与客户端连接(当客户端发起连接后，当服务器调用accept时，就会走三次握手建立连接)
             *    当连接建立后，就会与客户端SocketChannel来与客户端通信(双向通道)
             *    没有连接建立时，就会一直阻塞在这，有连接建立时，获取SocketChannel后会继续向下执行
             */
            log.info("connecting...");
            SocketChannel sc = ssc.accept();    //阻塞方法
            log.info("connected...{}", sc);
            channels.add(sc);
            for (SocketChannel channel : channels) {
                log.info("before read...{}", channel);
                //连接建立后，利用channel接收客户端发送的数据。读取不到数据就会阻塞
                channel.read(buffer);    //阻塞方法
                buffer.flip();
                ByteBufferUtil.debugAll(buffer);
                buffer.clear();
                log.info("after read...{}", channel);
            }
        }
        /**
         * 上面的演示中，我们发现单线程的阻塞服务器，只能同时做一件事
         * accept时就不能read(哪怕以前建立的连接channel上发生了可读事件)
         * read时不能accept(当执行到read时会一直等待channel上可读事件的发生，哪怕此时有新的连接进来也不会处理连接事件)
         */
    }
}
